package org.atlassian.plugins.fisheyeAutoReview;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.atlassian.crucible.spi.PluginId;
import com.atlassian.crucible.spi.data.ChangesetData;
import com.atlassian.crucible.spi.data.GeneralCommentData;
import com.atlassian.crucible.spi.data.ProjectData;
import com.atlassian.crucible.spi.data.ReviewData;
import com.atlassian.crucible.spi.services.ImpersonationService;
import com.atlassian.crucible.spi.services.Operation;
import com.atlassian.crucible.spi.services.ProjectService;
import com.atlassian.crucible.spi.services.ReviewService;
import com.atlassian.crucible.spi.services.SearchService;
import com.atlassian.event.Event;
import com.atlassian.event.EventListener;
import com.atlassian.fisheye.event.CommitEvent;
import com.atlassian.fisheye.spi.data.ChangesetDataFE;
import com.atlassian.fisheye.spi.services.RevisionDataService;

public class CommitListener implements EventListener {

	private static final Logger log = LoggerFactory.getLogger(CommitListener.class);

	private ProjectService projectService;
	private ReviewService reviewService;
	private SearchService searchService;
	private RevisionDataService revisionDataService;
	private ImpersonationService impersonationService;
	private PluginId pluginId;

	@Autowired
	public void setProjectService(ProjectService projectService) {
		this.projectService = projectService;
	}

	@Autowired
	public void setReviewService(ReviewService reviewService) {
		this.reviewService = reviewService;
	}

	@Autowired
	public void setSearchService(SearchService searchService) {
		this.searchService = searchService;
	}

	@Autowired
	public void setRevisionDataService(RevisionDataService revisionDataService) {
		this.revisionDataService = revisionDataService;
	}

	@Autowired
	public void setImpersonationService(ImpersonationService impersonationService) {
		this.impersonationService = impersonationService;
	}

	@Autowired
	public void setPluginId(PluginId pluginId)
	{
		this.pluginId = pluginId;
	}

	// @com.atlassian.event.api.EventListener
	public void onEvent(final CommitEvent event) {

		Set<String> idTokens = new HashSet<String>();

		ChangesetDataFE changeSet = revisionDataService.getChangeset(
				event.getRepositoryName(), event.getChangeSetId());
		final String comment = changeSet.getComment();

		for (ProjectData project : projectService.getAllProjects()) {
			Pattern p = Pattern.compile("(" + project.getKey() + "-[0-9]?)");
			Matcher m = p.matcher(comment);

			while (m.find()) {
				idTokens.add(m.group());
			}
		}

		for (String idToken : idTokens) {
			Set<ReviewData> reviews = new HashSet<ReviewData>(searchService
					.searchForReviews(idToken));

			for (final ReviewData review : reviews) {
				try {
					impersonationService.doAsUser(pluginId, changeSet.getAuthor(), new Operation<Void, Exception>() {
						@Override
						public Void perform() throws Exception {
							GeneralCommentData newComment = new GeneralCommentData();
							newComment.setMessage(ResourceBundle.getBundle("strings").getString("comment.prefix") + "\n" + comment);
							reviewService.addGeneralComment(review.getPermaId(), newComment);
							reviewService.addChangesetsToReview(review.getPermaId(), event
									.getRepositoryName(), Arrays
									.asList(new ChangesetData[] { new ChangesetData(event
											.getChangeSetId()) }));
							return null;
						}
					});
				} catch (Exception e) {
					log.error(e.getLocalizedMessage(), e);
				}

			}
		}
	}

	@Override
	public Class<?>[] getHandledEventClasses() {
		return new Class[] { CommitEvent.class };
	}

	@Override
	public void handleEvent(Event event) {
		onEvent((CommitEvent) event);
	}
}
